﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Transactions;
using System.Web;
using System.Web.Configuration;

namespace MvcMusicStore.Helpers
{
    public static class StorageHelper
    {
        private static readonly string ConnectionString = WebConfigurationManager.ConnectionStrings["MusicShopStorage"].ConnectionString;

        public static void UpdateSong(int id, Guid contentGuid, string contentType, Stream clientStream)
        {
            const string insertSql = @"
        UPDATE Song SET contentType = @ContentType, contentGuid = @ContentGuid, contentData = 0x0  WHERE Song.id = @Id
        SELECT contentData.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Song WHERE Song.id = @Id";

            string serverPath;
            byte[] filestreamTransaction;

            using (TransactionScope transaction = new TransactionScope())
            {
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();

                    using (SqlCommand cmd = new SqlCommand(insertSql, connection))
                    {
                        cmd.Parameters.Add("@ContentGuid", SqlDbType.UniqueIdentifier).Value = contentGuid;
                        cmd.Parameters.Add("@ContentType", SqlDbType.NVarChar).Value = contentType;
                        cmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;
                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            reader.Read();
                            serverPath = reader.GetSqlString(0).Value;
                            filestreamTransaction = reader.GetSqlBinary(1).Value;
                            reader.Close();
                        }
                    }
                    SaveMediaFile(clientStream, serverPath, filestreamTransaction);
                }
                transaction.Complete();
            }
        }

        private static void SaveMediaFile(Stream clientStream, string serverPath, byte[] filestreamTransaction)
        {
            const int blockSize = 1024 * 512;

            using (SqlFileStream dest = new SqlFileStream(serverPath, filestreamTransaction, FileAccess.Write))
            {
                byte[] buffer = new byte[blockSize];
                int bytesRead;
                while ((bytesRead = clientStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    dest.Write(buffer, 0, bytesRead);
                    dest.Flush();
                }
                dest.Close();
            }
        }

        public static void SelectSong(int id, out string contentType, out Stream clientStream, bool isDemo = true)
        {
            const string selectSql = @"
        SELECT contentData.PathName(), contentType, GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Song WHERE id = @Id";

            clientStream = new MemoryStream();
            string serverPath;
            byte[] filestreamTransaction;

            using (TransactionScope transaction = new TransactionScope())
            {
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();

                    using (SqlCommand cmd = new SqlCommand(selectSql, connection))
                    {
                        cmd.Parameters.Add("@Id", SqlDbType.Int).Value = id;

                        using (SqlDataReader reader = cmd.ExecuteReader())
                        {
                            if (!reader.HasRows) throw new ArgumentException();
                            reader.Read();
                            serverPath = reader.GetSqlString(0).Value;
                            contentType = reader.GetSqlString(1).Value;
                            filestreamTransaction = reader.GetSqlBinary(2).Value;
                            reader.Close();
                        }
                    }
                    LoadMediaFile(serverPath, clientStream, filestreamTransaction, isDemo);
                }

                transaction.Complete();
            }

        }

        private static void LoadMediaFile(string serverPath, Stream clientStream, byte[] filestreamTransaction, bool isDemo)
        {
            using (SqlFileStream source = new SqlFileStream(serverPath, filestreamTransaction, FileAccess.Read))
            {
                clientStream.Position = 0;

                const int blockSize = 1024 * 512;
                if (isDemo)
                {
                    int sourceLength = (int)source.Length;

                    int clientChunkLimit;
                    if (false == int.TryParse(WebConfigurationManager.AppSettings["ClientMediaDemoChunkLimit"], out clientChunkLimit))
                    {
                        clientChunkLimit = 20;
                    }

                    int clientChunkLength = sourceLength / 100 * clientChunkLimit;

                    byte[] buffer = new byte[blockSize];
                    int bytesRead;
                    int bytesCounter = 0;
                    while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0 && bytesCounter < clientChunkLength)
                    {
                        clientStream.Write(buffer, 0, bytesRead);
                        clientStream.Flush();
                        bytesCounter += bytesRead;
                    }
                }
                else
                {
                    source.CopyTo(clientStream);
                }

                clientStream.Position = 0;
            }
        }
    }
}